#include <input_kbdev.hpp>
#include <input_fingermoduledev.hpp>

#include <inputmanager.hpp>
#include <inputdev_func.hpp>
#include <string>
#include <elog.h>

#include <boost/thread.hpp>
#include <boost/asio.hpp>
#include <utils/timerfunc.hpp>
#include <time.h>
#include <sys/time.h>


using namespace std;


// UTF-8


static inputmanager* inputmanager_key;


// 全局
map<p_inmanager_cancel_func, char*> cancel_funcs;

static boost::asio::deadline_timer *ptimer;
static boost::asio::io_service *pio_timer;
// 将各个输入设备封装为单例模式


static timer_t Timer_inmanager_do_cancel_func;


inputmanager* inputdevFactory::create(char* devtype){

    if(strcmp(devtype, key_inputdev_type)== 0){
        
        return key_inputdev::pkey_inputdev_construct_instance();

    }else if(strcmp(devtype, fingermodule_inputdev_type)== 0){

        return fingermodule_inputdev::pfingermodule_inputdev_construct_instance();
    
    }else if(strcmp(devtype, all_inputdev_type)== 0){

         key_inputdev::pkey_inputdev_construct_instance();
         fingermodule_inputdev::pfingermodule_inputdev_construct_instance(); 
         
         return NULL;
    }

}


static inputdevFactory* Factory = new inputdevFactory;
inputmanager* inputdev          = NULL;


void inmanager_create_alldevs(void){

    Factory->create(all_inputdev_type);
}




    #if 0
        // 如果子类单例类的析构函数内部未重置单例指针为NULL，那么多次进入次函数会造成段错误。
        // (后续通过Factory->create重新获取实例时，就不会再次构造对象)
        int inmanager_enroll(char* devtype, input_dev_param *param){

            inputdev = Factory->create(devtype);  // 单例指针未重置为NULL，即使多次进入此函数，本质都只有一次构造
            inputdev->enroll(param);
            delete inputdev;  // 多次进入此函数，多次调用delete，会造成多次析够

            // 多次进入此函数，只有一次构造，却有多次析够，即使相关的析构函数的函数体都是空的，也会造成段错误。

        //换句话说，构造和析构一定是成对出现使用的。
        //不可以一次构造，多次析构(包括析构函数体为空的情况，
        //          即使调用的析构函数为空函数，也算一次析构)。

        }
    #endif

static int inmanager_enroll(char* devtype, input_dev_param *param){

    inputdev = Factory->create(devtype);
    inputdev->enroll(param);
    //delete inputdev;  // 提高效率，不析够。

    // 如果子类单例类的析构函数内部重置单例指针为了NULL，
    // 后续通过Factory->create重新获取实例时，就会再次构造对象。

    // 如果子类单例类的析构函数内部未重置单例指针为NULL
    // 后续通过Factory->create重新获取实例时，就不会再次构造对象。

     // 所以，此处不析构也可， 析够也可。效率不同而已。
}

/**************取消设备执行注册功能的回调函数，************
 * 参数param可以表征用户手动取消还是用户操作超时取消等信息******
 * *****************************************************/
static int inmanager_cancel_enroll(char* devtype, input_dev_param *param){

    inputdev = Factory->create(devtype);
    inputdev->cancel_enroll(param);
    //delete inputdev;
}

static int inmanager_authenticate(char* devtype, input_dev_param *param){

    inputdev = Factory->create(devtype);
    inputdev->authenticate(param);
    //delete inputdev;
}

static int inmanager_cancel_authenticate(char* devtype, input_dev_param *param){

    inputdev = Factory->create(devtype);
    inputdev->cancel_authenticate(param);
    //delete inputdev;
}

static int inmanager_get_userid(char* devtype, input_dev_param *param){

    inputdev = Factory->create(devtype);
    inputdev->get_userid(param);
    //delete inputdev;
}

static int inmanager_cancel_get_userid(char* devtype, input_dev_param *param){

    inputdev = Factory->create(devtype);
    inputdev->cancel_get_userid(param);
    //delete inputdev;
}

int inmanager_notify_signal(char* devtype, input_dev_param *param){

    inputdev = Factory->create(devtype);
    inputdev->notify_resource_to_inputdev(param);
    //delete inputdev;
}


int inmanager_notify_param_handle(char* devtype, input_dev_param *param){

    inputdev = Factory->create(devtype);
    inputdev->notify_param_handle(param);
    //delete inputdev;
}


string combine_devtypes(int num, ...){

    string ret, tmp;
    va_list valist;
    char* str = NULL;
    int i;
 
    /* 为 num 个参数初始化 valist */
    va_start(valist, num);
 
    /* 访问所有赋给 valist 的参数 */
    for (i = 0; i < num; i++)
    {
       str = va_arg(valist, char*);
       tmp = str;
       ret += tmp;

       if(i < num-1){
         tmp = magic_str;
         ret += tmp;
       }
    }

    /* 清理为 valist 保留的内存 */
    va_end(valist);
 
    return ret;
}

/*  使用boost定时器失败，我无法在A线程内取消B线程内的定时器任务。
    改为使用linux平台上的定时器。
static void timer_func(const boost::system::error_code& err)
{
   log_d("=============\n");

   if(err){
       // cancel 
       log_w("cancel_the_timer_inputdevfunc done!");
   }else{

       inmanager_do_cancel_func();
   }
}

static void timer(int seconds)
{
   boost::asio::io_service io;
   pio_timer = &io;
   boost::asio::deadline_timer timer(io, boost::posix_time::seconds(seconds));

   ptimer = &timer;
   
   timer.async_wait(timer_func);

   io.run();
}


void set_timer2callback_inputdevfunc(int seconds){

    boost::thread thread_timer2cancel(timer, seconds);
    thread_timer2cancel.detach();
}


void cancel_the_timer_inputdevfunc(void)
{
   pio_timer->stop();
    // ptimer->expires_from_now(boost::posix_time::millisec(0));
}
*/



static void timer_func(sigval_t param)
{
    log_d("cancel_the_timer_inputdevfunc !");

    int execption_info = combine_execption_info(input_execption_timeout, detail_operation_timeout_cancel);
    inmanager_do_cancel_func(execption_info);
}

void set_timer2callback_inputdevfunc(int seconds){

	memset(&Timer_inmanager_do_cancel_func, 0, sizeof(timer_t));
	get_timing()->init(timer_func, NULL, &Timer_inmanager_do_cancel_func);

	get_timing()->setUp(Timer_inmanager_do_cancel_func, seconds*1000, false); // false = do once
}


void cancel_the_timer_inputdevfunc(void)
{
   get_timing()->stop(Timer_inmanager_do_cancel_func);
}


/**************************************************************
 * ****************call 当前功能被取消时的回调函数*****************
**参数execption_info可以表征用户手动取消还是用户操作超时取消等信息*****
* ************ 该函数可以放在定时器回调函数内，实现定时调用************
****或者收到表示取消功能的功能键的触发信号后调用，实现用户取消当前设备功能**
*************************************************************/
void inmanager_do_cancel_func(int execption_info){   

        if(cancel_funcs.size()){

            map<p_inmanager_cancel_func, char*>::iterator iter;
            iter = cancel_funcs.begin();
            p_inmanager_cancel_func pfunc = iter->first;
            char* pdev_type = iter->second;

            if(pfunc){
                pfunc(pdev_type, reinterpret_cast<input_dev_param*>(execption_info)); 

                cancel_funcs.erase(cancel_funcs.begin(), cancel_funcs.end());      
            }
        }else{

            log_w("nothing to cancel!\n");
        }
}

/*************************************************************
 * ****************设置当前功能被取消时的回调函数******************
*************************************************************/
static void inmanager_cancel_func_set(p_inmanager_cancel_func p_func, char* devtype){
    
    cancel_funcs.erase(cancel_funcs.begin(), cancel_funcs.end());
    //log_d(" cancel_funcs.size = %d \n", cancel_funcs.size());

    cancel_funcs.insert(pair< p_inmanager_cancel_func, char* >(p_func, devtype)); 
    //log_d(" cancel_funcs.size = %d \n", cancel_funcs.size()); 
}

/*
//以注册函数为例
int inmanager_enroll_interface(char* devtype, input_dev_param *param){

    // 设备1执行注册的同时登记取消方法
    inmanager_enroll(const_cast<char*>(str_now.c_str()) , param);
    inmanager_cancel_enroll_set(inmanager_cancel_enroll, const_cast<char*>(str_now.c_str()),  NULL);

    // 。。。。省略


    // 设备2执行注册的同时也登记相应的取消方法
    inmanager_enroll(const_cast<char*>(str_now.c_str()) , param);
    inmanager_cancel_enroll_set(inmanager_cancel_enroll, const_cast<char*>(str_now.c_str()),  NULL);
}


然后：
在input_kbdev.cpp内部的key_input_event_listener函数内，
收到取消按键的按键值(可以是某个单一的功能键或者是组合键，例如连续两次快速按下C键)后，
就回调cancel_funcs对象内部的取消方法(遍历，回调所有取消方法),这样就实现了对发起注册功能的设备们的取消本次执行。
*/

static void inputmanager_do_job(string dev_type, e_inputmanager_cmd cmd, input_dev_param *param){

    char* s_dev_type = const_cast<char*>(dev_type.c_str()); 
    switch(cmd){

        case e_input_cmd_enroll:
        {
            /****************启动注册事件**************************/
            inmanager_enroll(s_dev_type, param);
            /****************设置注册事件被取消时的回调处理***********/
            inmanager_cancel_func_set(inmanager_cancel_enroll, s_dev_type);
        }
        break;

        case e_input_cmd_auth:
        {
            inmanager_authenticate(s_dev_type, param);
            // ？？？？？？？ 内部存储设备取消验证方法的容器的容量仅为1，这是不够的。
            // 多设备验证时，我们需要存储多个设备的取消验证的方法。
            // 所以，需要修改单个容器对象为一个容器链表或者数组。
            inmanager_cancel_func_set(inmanager_cancel_authenticate, s_dev_type);
        }
        break;

        case e_input_cmd_getid:
        {
            inmanager_get_userid(s_dev_type, param);
            inmanager_cancel_func_set(inmanager_cancel_get_userid, s_dev_type);
        }
        break;
    
        case e_input_cmd_notifystatus:
        {
            inmanager_notify_param_handle(s_dev_type, param);
        }
        break;

    default:
        assert(0);
        break;
    }

    if((e_input_cmd_enroll == cmd)||(e_input_cmd_auth == cmd)||(e_input_cmd_getid == cmd)){
        
        log_d("inputmanager_do_job: go to wait..param = 0x%x\n", param);
        boost::unique_lock<boost::mutex> lock(param->mutex); 
        param->cond.wait(lock); 

        log_d("inputmanager_do_job done! param->status  :     %d", param->status);
        log_d("inputmanager_do_job done! param->detail  :     %d", param->detail); 
        log_d("inputmanager_do_job done! param->isfuncdone:   %d", param->isfuncdone);
    }

}


/********************************************************
 * ???? 备注： 多设备验证时，下面的inputmanager_do_job会阻塞，
 * 所以需要将inputmanager_do_job的调用放在新开的线程内进行。
 * ******************************************************/
int inmanager_cmd(char* devtype, e_inputmanager_cmd cmd, input_dev_param *param){
  string *pstrlocal;
  string strnext;
  string strlocal;

  assert(param != NULL);

  if(devtype != NULL){
  	strlocal = devtype;
  }else{
	return -1;
  }
  pstrlocal = &strlocal;

  while(1){
    int pos = pstrlocal->find(magic_str);
    if(pos != pstrlocal->npos){

      string str_now = pstrlocal->substr(0, pos);
      //cout << "1 you can add substring_deal_func() here ...  str_now:" << str_now << endl;
      
      inputmanager_do_job(str_now, cmd, param);

      strnext = pstrlocal->substr(pos+1);  //截取从pos+1开始(包括0)到末尾的所有字符的子串, 并返回
      //cout << "str_next:" << strnext << endl;
      pstrlocal = &strnext;

    }else{

      string str_now = *pstrlocal;
      inputmanager_do_job(str_now, cmd, param);

      break;
    }
  }

}

/*
enum e_inputdev_status{
    e_kb_enroll_success = 1,
    e_kb_enroll_fail,  
};

enum input_curfunc_done{
    curfuncdone = 0, // 当前功能已经结束：
             // 例如，注册功能已结束，就是说注册所需的两步骤(第一次和第二次)已经完成了。
    
    curfuncnotdone,  // 当前功能未结束 
};
*/

